Security News
Fluent Assertions Faces Backlash After Abandoning Open Source Licensing
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
graphql-anywhere
Advanced tools
The graphql-anywhere package is a flexible utility for running GraphQL queries against any arbitrary data structure. It allows you to execute GraphQL queries on client-side data, making it useful for scenarios where you need to filter or transform data based on a GraphQL query.
Executing GraphQL queries on client-side data
This feature allows you to execute GraphQL queries on client-side data. The code sample demonstrates how to filter a data object based on a GraphQL query, returning only the fields specified in the query.
const { graphql } = require('graphql-anywhere');
const { filter } = require('graphql-anywhere/lib/async');
const query = `{
user {
name
age
}
}`;
const resolver = (fieldName, root, args, context, info) => {
return root[fieldName];
};
const data = {
user: {
name: 'John Doe',
age: 30,
email: 'john.doe@example.com'
}
};
filter(resolver, query, data).then(result => {
console.log(result);
// Output: { user: { name: 'John Doe', age: 30 } }
});
Custom resolvers for handling data
This feature allows you to define custom resolvers to handle data in a specific way. The code sample shows how to use a custom resolver to modify the 'age' field before returning the result.
const { graphql } = require('graphql-anywhere');
const { filter } = require('graphql-anywhere/lib/async');
const query = `{
user {
name
age
}
}`;
const customResolver = (fieldName, root, args, context, info) => {
if (fieldName === 'age') {
return root[fieldName] + 1; // Custom logic to modify the age
}
return root[fieldName];
};
const data = {
user: {
name: 'John Doe',
age: 30,
email: 'john.doe@example.com'
}
};
filter(customResolver, query, data).then(result => {
console.log(result);
// Output: { user: { name: 'John Doe', age: 31 } }
});
The graphql-tools package provides a set of utilities to build and manipulate GraphQL schemas in JavaScript. It includes features for schema stitching, mocking, and more. While graphql-tools focuses on schema creation and manipulation, graphql-anywhere is more about executing queries on arbitrary data structures.
Apollo Client is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. It includes features for caching, query batching, and more. While Apollo Client is a full-fledged GraphQL client, graphql-anywhere is a lightweight utility for executing queries on arbitrary data.
Run a GraphQL query anywhere, without a GraphQL server or a schema. Just pass in one resolver. Use it together with graphql-tag.
npm install graphql-anywhere graphql-tag
I think there are a lot of potentially exciting use cases for a completely standalone and schema-less GraphQL execution engine. We use it in Apollo Client to read data from a Redux store with GraphQL.
Let's come up with some more ideas - below are some use cases to get you started!
import graphql from 'graphql-anywhere'
graphql(resolver, document, rootValue?, context?, variables?, options?)
resolver
: A single resolver, called for every field on the query.
(fieldName, rootValue, args, context, info) => any
document
: A GraphQL document, as generated by the template literal from graphql-tag
rootValue
: The root value passed to the resolver when executing the root fieldscontext
: A context object passed to the resolver for every fieldvariables
: A dictionary of variables for the queryoptions
: Options for executionThe last argument to the graphql
function is a set of graphql-anywhere
-specific options.
resultMapper
: Transform field results after execution.
(resultFields, resultRoot) => any
fragmentMatcher
: Decide whether to execute a fragment. Default is to always execute all fragments.
(rootValue, typeCondition, context) => boolean
info
, the 5th argument to the resolver, is an object with supplementary information about execution. Send a PR or open an issue if you need additional information here.
isLeaf
: A boolean that is true
if this resolver is for a leaf field of the query, i.e. one that doesn't have a sub-selection.See http://dev.apollodata.com/react/fragments.html for examples of how you might use these.
import { filter } from 'graphql-anywhere'
filter(doc, data);
doc
: a GraphQL document, as generated by the template literal from graphql-tag
, typically either a query or a fragment.data
: an object of data to be filtered by the doc
Filter data
according to doc
.
import { check } from 'graphql-anywhere'
check(doc, data);
doc
: a GraphQL document, as generated by the template literal from graphql-tag
, typically either a query or a fragment.data
: an object of data, as may have been filtered by doc
.Check that data
is of the form defined by the query or fragment. Throw an exception if not.
import { propType } from 'graphql-anywhere'
X.propTypes = {
foo: propType(doc),
bar: propType(doc).isRequired,
}
doc
: a GraphQL document, as generated by the template literal from graphql-tag
, typically either a query or a fragment.Generate a React propType
checking function to ensure that the passed prop is in the right form.
Why do you even need a library for this? Well, running a GraphQL query isn't as simple as just traversing the AST, since there are some pretty neat features that make the language a bit more complex to execute.
@skip
and @include
directivesIf you come across a GraphQL feature not supported here, please file an issue.
import gql from 'graphql-tag';
import graphql from 'graphql-anywhere';
// I don't need all this stuff!
const gitHubAPIResponse = {
"url": "https://api.github.com/repos/octocat/Hello-World/issues/1347",
"title": "Found a bug",
"body": "I'm having a problem with this.",
"user": {
"login": "octocat",
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"url": "https://api.github.com/users/octocat",
},
"labels": [
{
"url": "https://api.github.com/repos/octocat/Hello-World/labels/bug",
"name": "bug",
"color": "f29513"
}
],
};
// Write a query that gets just the fields we want
const query = gql`
{
title
user {
login
}
labels {
name
}
}
`;
// Define a resolver that just returns a property
const resolver = (fieldName, root) => root[fieldName];
// Filter the data!
const result = graphql(
resolver,
query,
gitHubAPIResponse
);
assert.deepEqual(result, {
"title": "Found a bug",
"user": {
"login": "octocat",
},
"labels": [
{
"name": "bug",
}
],
});
// Write a query where the fields are types, but we alias them
const query = gql`
{
author {
name: string
age: int
address {
state: string
}
}
}
`;
// Define a resolver that uses the field name to determine the type
// Note that we get the actual name, not the alias, but the alias
// is used to determine the location in the response
const resolver = (fieldName) => ({
string: 'This is a string',
int: 5,
}[fieldName] || 'continue');
// Generate the object!
const result = graphql(
resolver,
query
);
assert.deepEqual(result, {
author: {
name: 'This is a string',
age: 5,
address: {
state: 'This is a string',
},
},
});
const data = {
result: [1, 2],
entities: {
articles: {
1: { id: 1, title: 'Some Article', author: 1 },
2: { id: 2, title: 'Other Article', author: 1 },
},
users: {
1: { id: 1, name: 'Dan' },
},
},
};
const query = gql`
{
result {
title
author {
name
}
}
}
`;
const schema = {
articles: {
author: 'users',
},
};
// This resolver is a bit more complex than others, since it has to
// correctly handle the root object, values by ID, and scalar leafs.
const resolver = (fieldName, rootValue, args, context): any => {
if (!rootValue) {
return context.result.map((id) => assign({}, context.entities.articles[id], {
__typename: 'articles',
}));
}
const typename = rootValue.__typename;
// If this field is a reference according to the schema
if (typename && schema[typename] && schema[typename][fieldName]) {
// Get the target type, and get it from entities by ID
const targetType: string = schema[typename][fieldName];
return assign({}, context.entities[targetType][rootValue[fieldName]], {
__typename: targetType,
});
}
// This field is just a scalar
return rootValue[fieldName];
};
const result = graphql(
resolver,
query,
null,
data // pass data as context since we have to access it all the time
);
// This is the non-normalized data, with only the fields we asked for in our query!
assert.deepEqual(result, {
result: [
{
title: 'Some Article',
author: {
name: 'Dan',
},
},
{
title: 'Other Article',
author: {
name: 'Dan',
},
},
],
});
You can use the resultMapper
option to convert your results into anything you like. In this case, we convert the result fields into children for a React component:
const resolver = (fieldName, root, args) => {
if (fieldName === 'text') {
return args.value;
}
return createElement(fieldName, args);
};
const reactMapper = (childObj, root) => {
const reactChildren = Object.keys(childObj).map(key => childObj[key]);
if (root) {
return cloneElement(root, root.props, ...reactChildren);
}
return reactChildren[0];
};
function gqlToReact(query): any {
return graphql(
resolver,
query,
'',
null,
null,
{ resultMapper: reactMapper },
);
}
const query = gql`
{
div {
s1: span(id: "my-id") {
text(value: "This is text")
}
s2: span
}
}
`;
assert.equal(
renderToStaticMarkup(gqlToReact(query)),
'<div><span id="my-id">This is text</span><span></span></div>'
);
FAQs
Run GraphQL queries with no schema and just one resolver
We found that graphql-anywhere demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 7 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.
Research
Security News
Socket researchers uncover the risks of a malicious Python package targeting Discord developers.
Security News
The UK is proposing a bold ban on ransomware payments by public entities to disrupt cybercrime, protect critical services, and lead global cybersecurity efforts.